package BNS.kingPawn;

import java.util.*;
import java.applet.Applet;
import java.awt.*;
import java.awt.event.*;
import java.rmi.*;
import javax.swing.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import BNS.graphs.*;
import BNS.plumbing.*;

/** The user interface needed by each player to play a MarketISGame.
	This sets up and operates all elements in the GUI.
	*/
	public class MarketISPersona extends BNSPersona {
	
	// TODO: should this be defined from kingPayRate?  (and pawnPayRate?)
	public static final float KingPremium= 1.0f;	
	
	protected ClientLiaisonInterface game;
	protected Graph graphlet;
	protected JComponent panel;
	protected StatusPanel statusPanel;
	protected ShowNodeTipsPanel graphPanel;	// hacked out ShowTipsPanel
	protected ControlPanel controlPanel;

	protected int timeLimit, progressLimit;
	protected int superSize, numNodes;
	protected float tip[];
	public static final Color panelBackground= Color.lightGray;
	
	/** This constructor just calls its superclass's constructor, with all
		the same parameters. It is intended to be called on the *server machine*,
		so that the 5 arguments here are stored in it; later the resulting object 
		is passed to the client where further setup is performed.
		*/
	public MarketISPersona(ClientLiaison g, Graph gr, int ssize, int time, int progress) { 
		game=g; graphlet=gr; timeLimit=time; progressLimit=progress;
		superSize= ssize;
		}
	
	/** returns the Node that is the eigennode for this graphlet.
		If the graph is the mastergraph, then this returns null.
		*/
	public Node getEigenNode() { return graphlet.eigenNode; }
	
	/** This method must be called after the constructor and before any use of the object.
		It is separated from the constructor because it contains a lot of constructions that
		should not be performed until the object has arrived on the *client machine*.
		For instance, the construction of the GUI elements such as JPanels should not be
		performed on the server. Herein, all the GUI elements are finally built, assembled,
		and made visible.
		*/
	public JComponent startPanel() {
		tip= new float[superSize];
		numNodes= graphlet.numNodes(); 
		panel= new JPanel();
		panel.setLayout(new BorderLayout());
		panel.setBackground(panelBackground);
		panel.setOpaque(true);
		
		statusPanel= new StatusPanel(timeLimit,progressLimit,true);
		panel.add("North", statusPanel);
		statusPanel.setMaximumSize(new Dimension(450,400));	// ANY limit seems to tame this
		
		graphPanel= new ShowNodeTipsPanel(ColorMap.identity());
		System.err.println("made ShowNodeTipsPanel");
		graphPanel.setDisplayNodes(true);
		panel.add("Center",graphPanel);
		graphPanel.init(graphlet);
		
		controlPanel= new ControlPanel(this,true);
		controlPanel.setOpaque(true);
		controlPanel.setBackground(panelBackground);
		panel.add("South", controlPanel);
		
		return panel;
		}
	
	/** returns the panel that may need to be torn down just before disposal of the Persona */
	public JComponent killPanel() { return panel; }
	
	/** Attempts to change the color of the player's node; handles error and exceptions */
	protected void setColor(int color) {
		try { if (!game.alter(new Integer(color)))
				System.err.println("color change not allowed"); }
		catch(RemoteException ex) { System.err.println(ex); }
		}
	
	/** Attempts to change the player's tipping amount; handles errors and exceptions */
	synchronized public boolean setTipRate(double newTip) {
		try { if (!game.alter(new Double(newTip))) {
				 System.err.println("tip change not allowed"); return false; }
			else 
				System.err.println(graphlet.eigenNode+" tip changed to "+newTip); 
			}
		catch(RemoteException ex) { System.err.println(ex); }
		return true;
		}
	
	/** returns the number of milliseconds that the client should wait before making another
		poll of the server for state updates.
		*/
	public int getCycleTime() { return 200; }
	
	/** Called by the Client object whenever it has successfully obtained an update of the
		game state from the server. 
		This game requires the dataBlob to be of type BNS.kingPawn.Envelope .
		This method unpacks the envelope and parcels out its components to the subroutines
		that handle each one.
		*/
	synchronized public void gameUpdate(java.io.Serializable dataBlob) {
		assert (dataBlob instanceof BNS.kingPawn.Envelope);
		BNS.kingPawn.Envelope envelope= (BNS.kingPawn.Envelope)dataBlob;
		setMessage(envelope.status);
		statusPanel.setWinStatus(envelope.local.winStatus);
		timerUpdate(envelope.elapsedTime);
		progressUpdate(envelope.currentProgress);
		statusPanel.setPay(envelope.local.payRate, envelope.local.cumulativePay);
		
		EdgeState[] edgeStates= envelope.local.edgeStates;
		for (int i=0; i<edgeStates.length; i++) {
			EdgeState edge= edgeStates[i];
			Node fr= graphlet.getNode(edge.frIdx);
			fr.color= edge.frRol==MarketISGame.KING? MarketISGame.kingInt : MarketISGame.pawnInt;
			Node to= graphlet.getNode(edge.toIdx);
			to.color= edge.toRol==MarketISGame.KING? MarketISGame.kingInt : MarketISGame.pawnInt;
			if (fr==graphlet.eigenNode) { 
			  tip[to.getIndex()]= edge.toTip;
			  tip[fr.getIndex()]= edge.frTip;
			  }
			if (to==graphlet.eigenNode) {
			  tip[fr.getIndex()]= edge.frTip;
			  tip[to.getIndex()]= edge.toTip;
			  }
			//System.err.print(" "+ n.lbl +" ["+ nidx +"]  value "+ n.color);
			}
		//System.err.println();
//		graphPanel.setEdgeStates(edgeStates);
		graphPanel.setNodeTips(tip);
		controlPanel.update(envelope.local.tFrac, envelope.local.kRate, envelope.local.pRate);
		graphPanel.repaint();
		}
	
	/** calculates how big this player's side payment to node nodeIdx can be at most, given 
		all the other current side payments. The sum is not allowed to exceed KingPremium.
		*/
	public float maxTip(int nodeIdx) {
		float totalTip= 0;
		for (int i=0; i<tip.length; i++) totalTip+= tip[i];
		//for (int i=0; i<tip.length; i++) System.err.print(" "+ tip[i]);
		//System.err.println("  <== tips "+tip[nodeIdx]);
		return KingPremium - (totalTip - tip[nodeIdx]);
		}
	
	/** updates the timer display in the GUI */
	public void timerUpdate(long elapsedTime) { statusPanel.timeBar.setValue((int)elapsedTime);	}
	
	/** updates the progress display in the GUI */
	public void progressUpdate(int progress) { 
		statusPanel.progressBar.setValue(progress); 
		String string= String.format("$%.2f/min",progress/1000.);
		statusPanel.progressBar.setString(string);
		}
	
	/** updates the status message display in the GUI */
	public void setMessage(String message) {
		if (message==null) return;
		statusPanel.messageBar.setText(message);
		Toolkit.getDefaultToolkit().beep();
		}
	
	/** returns a String identifying the type of game */
	public String getTitle() { return "MarketISPersona"; }
	
	} // EOC MarketISPersona
